﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using ATEC.GeometryNET;
using SSDPNET.Geom;
using ATEC.ATDataCoreNET;
using DynamicButtons;

namespace GeometryExample
{
    /// <summary>
    /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改。
    /// 内容：玄镜BIM图形平台上，修改几何对象，如点、线、面的例子.
    /// </summary>
    public class ModifyCurveSetMethods
    {
        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改。
        /// 功能：弹出三个按钮，分别演示查看原始线串（即多段线）、修改多段线的起终点、移动几何对象的例子。
        /// </summary>
        public static void ModifyGeometryExample()
        {
            //清空视口
            UseSomeBasicMethods.ClearScene();

            BasicCurve basicCrv = CreateCurveSetMethods.CreateLineStringFromPts();
            ButtonsView v = new ButtonsView();
            v.AddButton("查看原始线串", (object sender, RoutedEventArgs e) =>
            {
                //显示修改前的线串
                UseSomeBasicMethods.AddToScene_BasicCurve(basicCrv);
            });

            v.AddButton("修改起终点", (object sender, RoutedEventArgs e) =>
            {
                //修改起点
                XPoint3d ptSt = new XPoint3d(0, -50, 0);
                bool isSetStart = basicCrv.TrySetStart(ptSt);
                //修改终点
                XPoint3d pt = new XPoint3d(0, 50, 0);
                bool isSetEnd = basicCrv.TrySetEnd(pt);

                //查看修改后的线串
                UseSomeBasicMethods.AddToScene_BasicCurve(basicCrv, 4);
            });

            v.AddButton("移动几何对象", (object sender, RoutedEventArgs e) =>
            {
                //1. 给定移动矩阵
                XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(100, 0, 0));
                basicCrv.Transform(tranMoveTo);

                //查看修改后的线串
                UseSomeBasicMethods.AddToScene_BasicCurve(basicCrv, 5);
            });
            v.Show();
        }


        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线段。
        /// 功能：修改线段的起终点
        /// 关键类及说明：
        ///     XTransform3d: 变换操作类，包括旋转、缩放、平移操作.
        ///     XTransform3dExtension: 变换操作类 XTransform3d 的扩展类，提供额外的扩展方法
        /// 关键方法：
        ///     XTransform3d.FromTranslation: 根据向量XVector3d，构造一个平移效果的变换
        ///     XTransform3dExtension.Multiply: 将变换(XTransform3d)应用到几何对象（如XSegment3d、XRay、XEllipse3d)等上，实现旋转、缩放、平移等效果。
        /// </summary>
        public static void ModifyXSegment3dExample()
        {
            //1. 获取线段，并显示在视口
            XSegment3d seg1 = CreateCurveSetMethods.CreateHorizonXseg();
            UseSomeBasicMethods.AddToScene_XSegment(seg1);

            XSegment3d outSeg = seg1;
            //通过矩阵移动线段
            XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(100, 0, 0));
            tranMoveTo.Multiply(out outSeg, seg1);
            UseSomeBasicMethods.AddToScene_XSegment(outSeg, 3);

            //获取线段的坐标值
            double x0, y0, z0, x1, y1, z1;
            outSeg.Get(out x0, out y0, out z0, out x1, out y1, out z1);

            //修改线段的坐标值
            z0 += 10;
            z1 += 20;
            outSeg.Set(x0, y0, z0, x1, y1, z1);
            UseSomeBasicMethods.AddToScene_XSegment(outSeg, 4);
        }


        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)。
        /// 功能：动态生成6个按钮，每个按钮点击展示对应的例子，包括：1 偏移（Offset)线集(CurveSet)、2 分割线集 3 缩放线集 4 移除线集中的某种基本曲线（BasicCurve)
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///     CreateCurveSetMethods: 此类型包含一组创建线集（CurveSet)的方法，既可作为单独示例，展示玄镜平台几何创建的功能，也为当前修改示例服务。。
        ///     UseSomeBaicMethod:     玄镜平台的一些基本类，方便本修改用例使用，缩短示例代码，突出修改相关重点，使例子更简洁清晰。
        /// </summary>
        public static void ModifyCurveSetExample()
        {
            CurveSet curveForTest = CreateCurveSetMethods.CreateCurveSet();
            //偏移轮廓
            CurveSet curveTrans = curveForTest.Clone();

            ButtonsView v = new ButtonsView();
            v.AddButton("通过偏移矩阵移动轮廓", (object sender, RoutedEventArgs e) =>
            {
                curveTrans = TransformCurveSet(curveForTest);
                UseSomeBasicMethods.AddToScene_CurveSet(curveTrans, 1);
            });

            //偏移点集
            v.AddButton("通过偏移矩阵偏移移动轮廓的特征点", (object sender, RoutedEventArgs e) =>
            {
                //将curveForTest轮廓向X轴正方向偏移
                curveTrans = TransformPts(curveForTest.Clone());
                UseSomeBasicMethods.AddToScene_CurveSet(curveTrans, 2);
            });

            //分割轮廓
            CurveSet crvSplitter = TransformCurveSet(curveTrans.Clone()); //将curveTrans向Y轴正方向偏移后分割轮廓
            v.AddButton("分割轮廓", (object sender, RoutedEventArgs e) =>
            {
                crvSplitter = SplitCurve(crvSplitter);
                //分开显示BasicCurve查看分割效果
                for (int i = 0; i < crvSplitter.CountPrimitivesBelow(); i++)
                {
                    UseSomeBasicMethods.AddToScene_BasicCurve(crvSplitter.FindIndexedLeaf(i), i + 7);
                }
            });

            //对轮廓进行缩放
            CurveSet curveForOffset = TransformCurveSet(TransformCurveSet(curveTrans.Clone()));//将curveTrans向Y轴正方向偏移两次
            v.AddButton("对逆时针轮廓进行缩放", (object sender, RoutedEventArgs e) =>
            {
                OffsetCurve(curveForOffset.Clone()); //逆时针轮廓
            });

            v.AddButton("对顺时针轮廓进行缩放", (object sender, RoutedEventArgs e) =>
            {
                CurveSet curveCopy = TransformCurveSet(curveForOffset.Clone());//偏移，方便观察缩放效果
                curveCopy.ReverseCurvesInPlace();//将逆时针的轮廓反转成顺时针
                OffsetCurve(curveCopy);
            });

            //去掉轮廓中的Arc
            v.AddButton("去掉轮廓中的Arc", (object sender, RoutedEventArgs e) =>
            {
                CurveSet curveRemoveArc = RemoveArcFromCurve(curveForTest.Clone());
                UseSomeBasicMethods.AddToScene_CurveSet(curveRemoveArc, 3);
            });

            v.Show();
        }

        #region ModifyXEllipse
        public static void SetMethods()
        {
            XEllipse3d arc = CreateCurveSetMethods.CreateXEllipse3d_FromCenterStartEndPts();
            XEllipse3d arcCopy = XEllipse3dExtension.FromFractionInterval(arc, 0, 1);
            XEllipse3d arcCopy2 = XEllipse3dExtension.FromFractionInterval(arc, 0, 1);

            {//SetAngleRange设置圆弧的起终点角度
                XAngle angleAt = XAngle.PI;
                XAngle angleEd = XAngle.NEGATIVE_PI;
                arc.SetAngleRange(angleAt, angleEd);
            }
            //SetAngleRangeByFractions
            arcCopy.SetAngleRangeByFractions(0.2, 0.8);

            {//SetSweep设置扫掠角
                double angleAt = 0;
                double sweepIn = 90;
                arcCopy2.SetSweep(angleAt, sweepIn);
            }
        }

        public static void TransfromXEllipse()
        {
            //1. 计算移动矩阵
            XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(0, 50, 0));

            //2. 创建圆弧，添加到视口
            XEllipse3d arc1 = CreateCurveSetMethods.CreateXEllipse3d_FromCenterRadiusNormal();
            UseSomeBasicMethods.AddToScene_XEllipse3d(arc1);

            {
                //3. 移动圆弧，将移动后的圆弧添加到视口
                XEllipse3d outArc;
                tranMoveTo.Multiply( out outArc, arc1);           
                UseSomeBasicMethods.AddToScene_XEllipse3d(outArc, 3);
            }

        }


        #endregion

        #region ModifyCurveSet
        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何倒圆角。
        /// 功能：为线集CurveSet表示的形状（可以有是开放折线、或封闭多边形），倒圆角
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        /// 关键方法：
        ///     CurveSet.CloneWithFillets: 生成当前曲线的副本，并倒圆角，按照输入半径。返回副本。
        /// </summary>
        /// <param name="curve">要倒圆角的曲线</param>
        public static CurveSet FilletCurve(CurveSet curve)
        {
            //倒圆角，设置倒圆角的半径为50
            CurveSet fillet = curve.CloneWithFillets(50);
            return fillet;
        }

        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何分割线集
        /// 说明：玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用,因此也可说分割轮廓；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用，因此也可说分割曲线。
        /// 功能：为线集CurveSet表示的形状（可以有是开放折线、或封闭多边形），倒圆角
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.FindIndexedLeaf : 查找线集中的某条基本曲线（BasicCurve)，带序号
        ///     CurveSet.CloneBetweenFractions  : 复制线集的一段，按照指定的长度比例区间[a, b], [a, b]区间属于[0, 1]区间。玄镜平台线集(CurveSet)，用[0, 1]表示线集的全长。
        ///     CurveSet.CloneWithSplits  : 生成当前曲线的副本，并在与指定Splitter(另一曲线）的交点处分割各子曲线（BasicCurve)
        ///     CurveSet.CountPrimitivesBelow  : 返回当前线集中基本曲线（BasciCurve)的个数。
        /// </summary>
        /// <param name="curve">待分割的曲线</param>
        public static CurveSet SplitCurve(CurveSet curve)
        {
            double radius = 50;
            XVector3d normal = XVector3d.UnitZ;

            int count = curve.CountPrimitivesBelow(); //获取curve中 基础线段的个数
            int index = count > 1 ? 1 : 0;  //如果有多个基础线段，就取第2个，如果只有一个，就取第一个
            BasicCurve basicCrv = curve.GetPrimitive(index);//获取在index处的基础线元
            //int index = curve.FindIndexOfPrimitive(basicCrv);
            //截取基础线元的长度比例在0.2-0.7之间的一段，并找到中点
            BasicCurve fracCurve = basicCrv.CloneBetweenFractions(0.2, 0.7, false);
            XPoint3d st, ed;
            fracCurve.GetStartEnd(out st, out ed);
            XPoint3d centerPt = (st + ed) * 0.5;

            //在这个中点处创建一个圆作为分割的工具
            XEllipse3d arcSplitter = XEllipse3d.FromCenterRadiusNormal(centerPt, radius, normal);
            CurveSet splitterCurve = CurveSet.CreateDisk(arcSplitter, CurveSet.BoundaryType.Outer);
            UseSomeBasicMethods.AddToScene_CurveSet(splitterCurve, 7);

            //用分割工具分割线集合，将边界类型修改为open，否则线集合会被自动连起来
            CurveSet crvSplitter = curve.CloneWithSplits(splitterCurve);
            crvSplitter.SetBoundaryType(CurveSet.BoundaryType.Open);
            return crvSplitter;
        }

        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何偏移曲线
        /// 功能：对曲线CurveSet执行矩阵变换
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.TransformInPlace : 对曲线执行变换，InPlace 表示不生成副本，就地变换，即在 this 指向的CurveSet上变换.
        ///     CurveSet.Clone: 生成曲线的副本
        /// </summary>
        /// <param name="curve">待执行变换的曲线</param>
        public static CurveSet TransformCurveSet(CurveSet curveSet)
        {
            CurveSet curveCopy = curveSet.Clone();
            //设置偏移矩阵
            XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(0, 600, 0));

            curveCopy.TransformInPlace(tranMoveTo);
            return curveCopy;
        }


        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何获取线集（曲线）上的特征点，变换并重造曲线
        /// 功能：获取线集上的特征点，变换特征点，重造曲线
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.AddStrokePoints : 获取曲线上的特征点. 特征点指曲线轮廓路径上的关键点，如椭圆弧，该方法在弧的路径上采，返回足够表达原形状的采样点。
        /// </summary>
        /// <param name="curve">待采集特征点并变换、重建的曲线</param>
        public static CurveSet TransformPts(CurveSet curve)
        {
            //获取轮廓上所有的点
            List<XPoint3d> ptList = new List<XPoint3d>();
            curve.AddStrokePoints(out ptList, SSDPNET.Geom.FacetOptionsExtension.CreateForCurves()); //---调用崩溃

            XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(500, 0, 0));

            List<XPoint3d> ptListTrans = new List<XPoint3d>();
            tranMoveTo.Multiply( ptListTrans, ptList, ptList.Count());
       
            //通过点集创建线集合
            CurveSet lineCrv = CurveSet.CreateLinear(ptListTrans, CurveSet.BoundaryType.Outer, false);
            return lineCrv;
        }

        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何偏移（Offset)曲线
        /// 功能：偏移(Offset）指定的曲线. Offst对于曲线，会有缩放效果. 因此也可说，如何“缩放”曲线
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.CloneOffsetCurvesXY : 生成曲线的副本，并执行Offset操作
        ///         参数说明：(double distance-偏移距离, double arcRadians--圆倒角弧度, double jointRadians--倒角弧度);
        ///         缩放效果的说明：曲线（CurveSet)本身的顺逆时针方向，决定是缩小还是放大：
        ///            轮廓--CCW(逆时针)--distance 大于 0--放大
        ///            轮廓--CCW(逆时针)--distance 小于 0--缩小
        ///            轮廓--CW(顺时针)--相反
        /// </summary>
        public static void OffsetCurve(CurveSet curve)
        {
            CurveSet copyCurve = curve.Clone();
            UseSomeBasicMethods.AddToScene_CurveSet(copyCurve);

            //轮廓--CCW--distance 大于 0--放大
            //轮廓--CW--相反
            CurveSet newCurve = copyCurve.CloneOffsetCurvesXY(-10, 0, Math.PI * 0.5);
            UseSomeBasicMethods.AddToScene_CurveSet(newCurve, 1);

            CurveSet crv1 = copyCurve.CloneOffsetCurvesXY(10, 0, Math.PI * 0.5);
            UseSomeBasicMethods.AddToScene_CurveSet(crv1, 2);
        }

        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何去除线集中的圆弧
        /// 功能：查找线集中类型为圆弧（BasicCurve.BasicCurveType.Arc)的基本曲线，并去除之。
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.GetPrimitive(i) : 获取线集中序号（从0开始）为i的基本曲线，返回的为子曲线本身，不是副本。
        ///     BasicCurve.GetBasicCurveType : 查询基本曲线（BasiceCurve)的类型
        ///         常见基本曲线类型说明:
        ///         public enum BasicCurveType
        ///         {
        ///             None = 0,       // 未设置
        ///             Invalid = 0,    // 无效类型
        ///             Line = 1,       // 直线
        ///             LineString = 2, // 多段线
        ///             Arc = 3,        // 圆弧
        ///             BsplineCurve = 4, // B样条曲线
        ///             InterpolationCurve = 5,
        ///             z0e0f1c63a7 = 6,
        ///             PointString = 7,    // 点集
        ///             CurveSet = 8,       // 线集
        ///             Spiral = 9,         // 螺旋线
        ///             zf69512774c = 10
        ///         }
        /// </summary>
        public static CurveSet RemoveArcFromCurve(CurveSet curve)
        {
            if (curve == null)
            {
                return null;
            }
            CurveSet newCurve = CurveSet.Create(CurveSet.BoundaryType.None);
            for (int i = 0; i < curve.Count; i++)
            {
                //找到CurveSet中 BasicCurve类型不是圆弧的部分，加到新的Curve中
                if (curve.GetPrimitive(i).GetBasicCurveType() != BasicCurve.BasicCurveType.Arc)
                {
                    newCurve.Add(curve.GetPrimitive(i));
                }
            }
            return newCurve;
        }


        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何去除曲线各段间的缝隙
        /// 功能：修复线集内各基本曲线连接处的缝隙. 通过补线（端点间插值，连接端点、构造B样条曲线通过原端点）、延长原曲线、修改原曲线端点、重采样拟合等方法.
        /// 关键类及说明：
        ///     CurveSet: BasicCurve的集合。此类可以是一组没有关系的BasicCurve，也可以组合多个BasicCurve，表达封闭多边形、开放线条，进而可以进行求交、分割、求面积等操作.
        ///               玄镜平台几何话题，大多数场景下，线集与“轮廓”经常互用；线集与“曲线”(广义的，封闭、非封闭；平面、非平面)经常互用.
        /// 关键方法：
        ///     CurveSet.CloneWithGapsClosed : 修复曲线各段间的缝隙
        ///     CurveGapOptions : 修复缝隙时的选项，如：
        ///         - 判断是否已经相接的容差: SetEqualPointTolerance
        ///         - 直接修改曲线端点时，最大容差: SetMaxDirectAdjustTolerance
        public static void CloneGap()
        {
            CurveSet curveClose = CreateCurveSetMethods.CreateCurveSet();
            CurveSet curveGap = RemoveArcFromCurve(curveClose);
            XPoint3d stPt, edPt;
            curveGap.GetStartEnd(out stPt, out edPt);

            edPt -= XVector3d.UnitX * 10;
            BasicCurve line = BasicCurve.CreateLine(new XSegment3d(stPt, edPt));
            curveGap.Add(line);
            //UseSomeBasicMehtods.AddToScene_CurveSet(curveGap, 3);

            double dEnoughLong = 1000;
            SSDPNET.CurveGapOptions opt = new SSDPNET.CurveGapOptions();
            opt.SetMaxDirectAdjustTolerance(dEnoughLong);
            opt.SetEqualPointTolerance(0);
            CurveSet newCurvesNoGap = curveGap.CloneWithGapsClosed(opt);
            //UseSomeBasicMehtods.AddToScene_CurveSet(newCurvesNoGap, 4);
        }

        #endregion

        #region ModifyBSplineCurve
        /// <summary>
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/几何/修改/修改线集(CurveSet)/如何对B样条曲线执行变换
        /// 功能：对B样条曲线（ATBsplineCurve)执行变换 (XTransform3d)
        /// 关键类及说明：
        ///     ATBsplineCurve: B样条曲线
        /// 关键方法：
        ///     ATBsplineCurve.Transform : 对B条样曲线执行变换
        public static ATBsplineCurve TransformBsplineCurve(ATBsplineCurve bsplineCurve)
        {
            XTransform3d tranMoveTo = XTransform3d.FromTranslation(XVector3d.FromXYZ(0, 50, 0));

            bool isSuccess = bsplineCurve.Transform(ref tranMoveTo);
            UseSomeBasicMethods.AddToScene_ATBsplineCurve(bsplineCurve, 2);

            return bsplineCurve;
        }
        #endregion

    }
}
